package cc.eguid.tools;

import cc.eguid.tools.msg.*;
import cc.eguid.tools.utils.ImageCompress;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Iterator;

/**
 * 服务端实现
 */
public class RemoteServer implements Runnable {
    private int port;
    private ServerSocket serverSocket;
    private Socket clientSocket;
    private ObjectOutputStream out;
    private ObjectInputStream in;
    private Robot robot;
    private boolean running;
    private Rectangle screenRect;

    // 令牌字段
    private String validToken;

    private Float imageQuality = 1F;

    public RemoteServer(int port, String token) {
        this.port = port;
        this.validToken = token;
        try {
            robot = new Robot();
            screenRect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
        } catch (AWTException e) {
            throw new RuntimeException("无法创建Robot实例", e);
        }
    }

    @Override
    public void run() {
        try {
            serverSocket = new ServerSocket(port);
            running = true;
            System.out.println("服务端启动，等待客户端连接...");

            // 循环等待客户端连接
            while (running) {
                try {
                    // 等待客户端连接
                    clientSocket = serverSocket.accept();
                    System.out.println("客户端已连接: " + clientSocket.getRemoteSocketAddress());

                    out = new ObjectOutputStream(clientSocket.getOutputStream());
                    in = new ObjectInputStream(clientSocket.getInputStream());

                    // 处理客户端连接
                    if (handleClientConnection()) {
                        // 连接成功，处理客户端事件
                        handleClientEvents();
                    }
                } catch (IOException e) {
                    if (running) {
                        System.out.println("客户端连接异常: " + e.getMessage());
                    }
                } finally {
                    // 清理当前连接
                    cleanupClientConnection();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            stop();
        }
    }

    // 多客户端简化支持（示例）：暴露断开当前客户端的方法
    public synchronized void disconnectCurrentClient() {
        try {
            if (clientSocket != null && !clientSocket.isClosed()) {
                clientSocket.close();
            }
        } catch (IOException ignored) {
        }
    }

    public synchronized String getCurrentClientAddress() {
        return clientSocket == null ? "" : String.valueOf(clientSocket.getRemoteSocketAddress());
    }

    // 处理客户端连接和验证
    private boolean handleClientConnection() {
        try {
            // 等待客户端发送令牌
            Object obj = in.readObject();
            if (obj instanceof TokenMessage) {
                TokenMessage tokenMsg = (TokenMessage) obj;
                if (validToken.equals(tokenMsg.getToken())) {
                    // 令牌验证通过
                    out.writeObject(new AuthMessage(true, "验证成功"));
                    out.flush();
                    System.out.println("客户端令牌验证通过");
                    return true;
                } else {
                    // 令牌验证失败
                    out.writeObject(new AuthMessage(false, "令牌错误"));
                    out.flush();
                    System.out.println("客户端令牌验证失败");
                    return false;
                }
            } else {
                // 协议错误
                out.writeObject(new AuthMessage(false, "协议错误"));
                out.flush();
                System.out.println("协议错误");
                return false;
            }
        } catch (Exception e) {
            System.out.println("处理客户端连接时发生异常: " + e.getMessage());
            return false;
        }
    }

    // 处理客户端事件
    private void handleClientEvents() {
        // 启动屏幕捕获线程
        Thread screenThread = new Thread(this::captureScreen);
        screenThread.setDaemon(true);
        screenThread.start();

        // 处理客户端事件
        while (running && clientSocket != null && !clientSocket.isClosed()) {
            try {
                Object eventObj = in.readObject();
                if (eventObj instanceof MouseEventMessage) {
                    handleMouseEvent((MouseEventMessage) eventObj);
                } else if (eventObj instanceof KeyEventMessage) {
                    handleKeyEvent((KeyEventMessage) eventObj);
                } else if (eventObj instanceof InstructionMessage) {
                    handleInstructionMessage((InstructionMessage) eventObj);
                }
            } catch (EOFException e) {
                System.out.println("客户端断开连接");
                break;
            } catch (Exception e) {
                System.out.println("处理客户端事件时发生异常: " + e.getMessage());
                break;
            }
        }
    }

    // 清理客户端连接
    private void cleanupClientConnection() {
        try {
            if (in != null) {
                in.close();
                in = null;
            }
            if (out != null) {
                out.close();
                out = null;
            }
            if (clientSocket != null) {
                clientSocket.close();
                clientSocket = null;
            }
            System.out.println("客户端连接已清理");
        } catch (IOException e) {
            System.out.println("清理客户端连接时发生异常: " + e.getMessage());
        }
    }

    private void captureScreen() {
        while (running && clientSocket != null && !clientSocket.isClosed()) {
            try {
                BufferedImage screenImage = robot.createScreenCapture(screenRect);
                float useQuality = imageQuality;
                //动态可调图像压缩比
                ImageMessage imageMessage = new ImageMessage(ImageCompress.compressBufferedImage(screenImage, useQuality));

                out.writeObject(imageMessage);
                out.flush();
                out.reset(); // 重置流以避免缓存问题

                Thread.sleep(1000 / 25); // 25 FPS
            } catch (Exception e) {
                break;
            }
        }
    }

    private void handleMouseEvent(MouseEventMessage event) {
        switch (event.getType()) {
            case "PRESSED":
                robot.mousePress(mapAwtButtonToMask(event.getButton()));
                break;
            case "RELEASED":
                robot.mouseRelease(mapAwtButtonToMask(event.getButton()));
                break;
            case "MOVED":
                robot.mouseMove(event.getX(), event.getY());
                break;
            case "DRAGGED":
                robot.mouseMove(event.getX(), event.getY());
                break;
        }
    }

    private int mapAwtButtonToMask(int awtButton) {
        switch (awtButton) {
            case java.awt.event.MouseEvent.BUTTON1:
                return java.awt.event.InputEvent.BUTTON1_DOWN_MASK;
            case java.awt.event.MouseEvent.BUTTON2:
                return java.awt.event.InputEvent.BUTTON2_DOWN_MASK;
            case java.awt.event.MouseEvent.BUTTON3:
                return java.awt.event.InputEvent.BUTTON3_DOWN_MASK;
            default:
                return java.awt.event.InputEvent.BUTTON1_DOWN_MASK;
        }
    }

    private void handleKeyEvent(KeyEventMessage event) {
        switch (event.getType()) {
            case "PRESSED":
                robot.keyPress(event.getKeyCode());
                robot.keyRelease(event.getKeyCode());//强制释放按键，防止服务端按键输入混乱
                break;
            case "RELEASED":
                robot.keyRelease(event.getKeyCode());
                break;
            case "TYPED":
                if (event.getKeyChar() != KeyEvent.CHAR_UNDEFINED) {
                    // 对于字符输入，需要模拟按下和释放
                    int keyCode = KeyEvent.getExtendedKeyCodeForChar(event.getKeyChar());
                    if (keyCode != KeyEvent.VK_UNDEFINED) {
                        robot.keyPress(keyCode);
                        robot.keyRelease(keyCode);
                    }
                }
                break;
        }
    }

    private void handleInstructionMessage(InstructionMessage instructionMessage) {
        switch (instructionMessage.getInstructionEnum()) {
            case IMAGE_QUALITY:
                imageQuality = instructionMessage.getData().getFloat("quality");
                break;
            default:
                break;
        }
    }

    public void stop() {
        running = false;
        try {
            // 清理客户端连接
            cleanupClientConnection();

            // 关闭服务器socket
            if (serverSocket != null) {
                serverSocket.close();
                serverSocket = null;
            }
            System.out.println("服务端已停止");
        } catch (IOException e) {
            System.out.println("停止服务端时发生异常: " + e.getMessage());
        }
    }

}
